package verify

import (
	"errors"
	"image/color"
	"time"

	"github.com/mojocn/base64Captcha"
)

const (
	CaptchaTypeDigit = "digit"
	CaptchaTypeMath  = "math"
)

type CaptchaConf struct {
	Type    string `json:"type"` // "digit" "string" "math"
	Width   uint32 `json:"width"`
	Height  uint32 `json:"height"`
	KeyLong uint32 `json:"keyLong"`
}

type CaptchaResult struct {
	CaptchaId string `json:"CaptchaId"`
	Data      string `json:"Data"`
	Expire    uint32 `json:"expire"`
}

var (
	// GCLimitNumber The number of captchas created that triggers garbage collection used by default store.
	GCLimitNumber = 1024
	// Expiration time of captchas used by default store.
	Expiration = 3 * time.Minute
	// DefaultMemStore is a shared storage for captchas, generated by New function.
	captchaStore = base64Captcha.NewMemoryStore(GCLimitNumber, Expiration)
)

func new(driver base64Captcha.Driver) (result *CaptchaResult, err error) {
	cp := base64Captcha.NewCaptcha(driver, captchaStore)
	id, b64s, err := cp.Generate()
	if err != nil {
		return nil, err
	}

	result = &CaptchaResult{
		CaptchaId: id,
		Data:      b64s,
		Expire:    uint32(Expiration.Seconds()),
	}
	return result, err
}

func newDigit(c *CaptchaConf) (result *CaptchaResult, err error) {
	driver := base64Captcha.NewDriverDigit(int(c.Height), int(c.Width), int(c.KeyLong), 0.7, 80)
	return new(driver)
}

func newMath(c *CaptchaConf) (result *CaptchaResult, err error) {
	driver := base64Captcha.NewDriverMath(int(c.Height), int(c.Width), 0,
		0, &color.RGBA{R: 244, G: 255, B: 244, A: 244}, nil, []string{"3Dumb.ttf"})
	return new(driver)
}

func NewCaptcha(c *CaptchaConf) (result *CaptchaResult, err error) {
	if c.Height < 40 || c.Height > 400 {
		return nil, errors.New("height param error")
	}

	if c.Width < 100 || c.Height > 400 {
		return nil, errors.New("width param error")
	}

	switch c.Type {
	case CaptchaTypeDigit:
		return newDigit(c)
	case CaptchaTypeMath:
		return newMath(c)
	}

	return nil, errors.New("not support")

}

func Verify(id, answer string, clear bool) bool {
	if 0 == len(id) || 0 == len(answer) {
		return false
	}
	return captchaStore.Verify(id, answer, clear)
}
